package main

/**
获取板块信息
*/
import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"

	_ "github.com/go-sql-driver/mysql"
)

/*
f12: "BK0843"
f13: 90
f14: "天然气"
f62: 1669601856
*/

type GnDiff struct {
	Code        string  `json:"f12"` // 板块代码
	F13         int     `json:"f13"` // 90
	BkName      string  `json:"f14"` // 板块名
	F62         float64 `json:"f62"` // 今日主力净流入-净额
	Delflag     bool
	Create_time time.Time
	Modify_time time.Time
}

type Gnbk struct {
	Data struct {
		Total int      `json:"total"`
		Diff  []GnDiff `json:"diff"`
	} `json:"data"`
}

// fetchData 获取数据并处理JSONP响应
func fetchData(url string) ([]byte, []byte, error) {
	referer := "https://data.eastmoney.com/bkzj/gn.html"

	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Println("创建请求失败:", url, nil)
		return nil, nil, err
	}
	req.Header.Add("Referer", referer)
	req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
	resp, err := client.Do(req)
	fmt.Println(url)
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, nil, err
	}

	// 处理JSONP响应：提取JSON部分
	re := regexp.MustCompile(`\w+\(([\s\S]*)\);?$`)
	matches := re.FindStringSubmatch(string(body))

	var jsonData string
	if len(matches) > 1 {
		jsonData = matches[1]
	} else {
		jsonData = string(body)
	}
	// fmt.Println(string(jsonData))

	return []byte(jsonData), body, nil
}

func buildInsertSQL(tableName string, columns, updateColumns []string) string {

	// 构造 INSERT 部分
	placeholder := strings.Repeat("?, ", len(columns)-1) + "?"
	insertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", tableName, strings.Join(columns, ", "), placeholder)

	// 构造 ON DUPLICATE KEY UPDATE 部分
	updateExpr := make([]string, len(updateColumns))
	for i, col := range updateColumns {
		updateExpr[i] = fmt.Sprintf("%s = VALUES(%s)", col, col)
	}
	finalSQL := fmt.Sprintf("%s ON DUPLICATE KEY UPDATE %s", insertSQL, strings.Join(updateExpr, ", "))

	return finalSQL
}

func main() {
	db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/stock?parseTime=true")
	if err != nil {
		fmt.Println("无法打开数据库:", err)
		return
	}
	defer db.Close()

	err = db.Ping()
	if err != nil {
		fmt.Println("无法连接到数据库:", err)
		return
	}

	GnbkURL := "https://data.eastmoney.com/dataapi/bkzj/getbkzj?key=f62&code=m:90+t:3"
	gnbkData, respBody, err := fetchData(GnbkURL)

	if err != nil {
		fmt.Printf("概念板块数据获取失败: %v\n", err)
	} else {
		var gnbk Gnbk
		if err := json.Unmarshal(gnbkData, &gnbk); err != nil {
			fmt.Printf("概念板块数据解析失败: %v\n", err)
			fmt.Printf("原始响应前200字符: %s\n", string(respBody)[:200])
		} else {

			existingCodes := getExistingCodes(db)
			fmt.Println(len(existingCodes))
			for _, gndiff := range gnbk.Data.Diff {
				if flag, exists := existingCodes[gndiff.Code]; exists {
					// fmt.Printf("Record with code %s already exists, skipping.\n", gndiff.Code)
					if !flag {
						updateRecord(db, gndiff)
					}
				} else {
					insertRecord(db, gndiff)
				}
			}

			deleteNonExistentRecords(db, gnbk.Data.Diff)

			fmt.Printf("概念板块数据获取成功: %d只股票\n", len(gnbk.Data.Diff))
		}
	}
}

func getExistingCodes(db *sql.DB) map[string]bool {
	codes := make(map[string]bool)
	rows, err := db.Query("SELECT code,delflag FROM gnbk")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var code string
		var flag int
		if err := rows.Scan(&code, &flag); err != nil {
			log.Fatal(err)
		}
		if flag == 0 {
			codes[code] = true
		} else {
			codes[code] = false
		}
	}

	return codes
}

func insertRecord(db *sql.DB, gndiff GnDiff) {
	query := "INSERT INTO gnbk (Code, F13, BkName, F62, Create_time, Modify_time) VALUES (?, ?, ?, ?, ?, ?)"
	_, err := db.Exec(query, gndiff.Code, gndiff.F13, gndiff.BkName, gndiff.F62, time.Now(), time.Now())
	if err != nil {
		log.Println("Error inserting record:", err)
	} else {
		// fmt.Printf("Inserted record with code %s\n", gndiff.Code)
	}
}

func updateRecord(db *sql.DB, gndiff GnDiff) {
	fmt.Println("update")
	updateSQL := "UPDATE gnbk set F13=?,bKName=?,F62=?,Modify_time=?,delflag=? where code=?"
	_, err := db.Exec(updateSQL, gndiff.F13, gndiff.BkName, gndiff.F62, time.Now(), 0, gndiff.Code)
	if err != nil {
		log.Println("Error update record:", err)
	} else {
		// fmt.Printf("Inserted record with code %s\n", gndiff.Code)
	}
}

func deleteNonExistentRecords(db *sql.DB, gnDiffs []GnDiff) {
	newCodesMap := make(map[string]bool)
	for _, gndiff := range gnDiffs {
		newCodesMap[gndiff.Code] = true
	}

	rows, err := db.Query("SELECT Code FROM gnbk WHERE Delflag = 0")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		var code string
		if err := rows.Scan(&code); err != nil {
			log.Fatal(err)
		}
		if !newCodesMap[code] {
			updateQuery := "UPDATE gnbk SET Delflag = 0,modify_time=? WHERE Code = ?"
			_, err := db.Exec(updateQuery, time.Now(), code)
			if err != nil {
				log.Println("Error updating record:", err)
			} else {
				fmt.Printf("Updated record with code %s to set Delflag to true\n", code)
			}
		}
	}
}
